package ch.exploadingelephants.model;

import java.io.Serializable;

import ch.exploadingelephants.graph.DotString;
import ch.exploadingelephants.graph.InfinityLoopException;
import ch.exploadingelephants.graph.MachineGraph;
import ch.exploadingelephants.graph.TokenResult;

/**
 * @author Sandro De Zanet
 * 
 *         This class describes a level to beat. It consists of the starting
 *         situation (Machine), a solution graph and a description of what has
 *         to be achieved
 */
public class Level implements Serializable {
    private Machine machine;
    private MachineGraph solution;
    private String title;
    private String description;
    private final boolean endStringMatch;// if true, additionally checks
					 // if the resulting string is
					 // equal
    // Uniquely identifies the level, is needed to identify levels by file
    private final String identifier;

    /**
     * 
     */
    public Level() {
	this(Integer.valueOf((int) (10000 * Math.random())).toString(), false);
    }

    /**
     * @param identifier
     * @param endStringMatch
     */
    public Level(String identifier, boolean endStringMatch) {
	this.title = identifier;
	this.identifier = identifier;
	this.endStringMatch = endStringMatch;
    }

    /**
     * @param title
     *            the title to set
     */
    public void setTitle(String title) {
	this.title = title;
    }

    /**
     * @param description
     */
    public void setDescription(String description) {
	this.description = description;
    }

    /**
     * @param machine
     */
    public void setMachine(Machine machine) {
	this.machine = machine;
    }

    /**
     * @param solution
     */
    public void setSolution(MachineGraph solution) {
	this.solution = solution;
    }

    /**
     * @return
     */
    public Machine getMachine() {
	return this.machine;
    }

    /**
     * @return
     */
    public String getDescription() {
	return this.description;
    }

    /**
     * @param machineGraph
     * @return
     */
    public EvaluationResult evaluate(MachineGraph machineGraph) {
	DotStringGenerator generator = new DotStringGenerator(10);
	while (generator.hasNext()) {
	    DotString string = generator.next();
	    TokenResult userResult;
	    try {
		userResult = machineGraph.run(string.copy());
	    } catch (InfinityLoopException e) {
		return new EvaluationResult(EvaluationStatus.INFINITE_LOOP,
			string);
	    }
	    TokenResult expectedResult;
	    try {
		expectedResult = solution.run(string.copy());
	    } catch (InfinityLoopException e) {
		return new EvaluationResult(
			EvaluationStatus.LEVEL_INCONSISTENT, string);
	    }
	    if (userResult.isAccept() && !expectedResult.isAccept()) {
		return new EvaluationResult(EvaluationStatus.SHOULD_REJECT,
			string);
	    } else if (!userResult.isAccept() && expectedResult.isAccept()) {
		return new EvaluationResult(EvaluationStatus.SHOULD_ACCEPT,
			string);
	    } else if (endStringMatch
		    && !(userResult.getString().equals(expectedResult
			    .getString()))) {
		return new EvaluationResult(EvaluationStatus.WRONG_OUTPUT,
			string);
	    }
	}
	return new EvaluationResult(EvaluationStatus.OK, null);
    }

    /**
     * @return
     */
    public String getTitle() {
	return title;
    }

    /**
     * @return
     */
    public String getIdentifier() {
	return this.identifier;
    }
}
